package com.agileboot.domain.performance.score;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 用户分数统计任务队列管理器
 * 实现异步任务队列，确保同一时间只有一个任务在执行
 * 相同userId的任务会被合并为一个
 */
@Slf4j
@Component
public class UserScoreCalculationQueue {

    private final BlockingQueue<Long> taskQueue = new LinkedBlockingQueue<>();
    private final Set<Long> pendingUserIds = new HashSet<>();
    private final ReentrantLock lock = new ReentrantLock();
    private ExecutorService executorService;
    private volatile boolean running = true;

    @Autowired
    @Lazy
    private UserScoreRecordApplicationService userScoreRecordApplicationService;

    @PostConstruct
    public void init() {
        // 创建单线程执行器
        executorService = Executors.newSingleThreadExecutor(r -> {
            Thread thread = new Thread(r, "UserScoreCalculation-Thread");
            thread.setDaemon(true);
            return thread;
        });
        // 启动任务处理线程
        executorService.submit(this::processTasks);
        log.info("用户分数统计任务队列管理器已启动");
    }

    @PreDestroy
    public void destroy() {
        running = false;
        if (executorService != null) {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        log.info("用户分数统计任务队列管理器已关闭");
    }

    /**
     * 提交统计任务
     * 如果队列中已有相同userId的任务，则不会重复添加
     * @param userId 用户ID
     */
    public void submitTask(Long userId) {
        if (userId == null) {
            return;
        }

        lock.lock();
        try {
            // 如果该userId已经在队列中或正在处理，则不重复添加
            if (pendingUserIds.contains(userId)) {
                log.debug("用户ID {} 的统计任务已在队列中，跳过重复添加", userId);
                return;
            }
            pendingUserIds.add(userId);
            taskQueue.offer(userId);
            log.debug("用户ID {} 的统计任务已加入队列", userId);
        } finally {
            lock.unlock();
        }
    }

    /**
     * 任务处理循环
     */
    private void processTasks() {
        while (running) {
            try {
                // 从队列中取出任务，最多等待5秒
                Long userId = taskQueue.poll(5, TimeUnit.SECONDS);
                if (userId != null) {
                    lock.lock();
                    try {
                        pendingUserIds.remove(userId);
                    } finally {
                        lock.unlock();
                    }
                    // 执行统计任务
                    executeCalculation(userId);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("任务处理线程被中断", e);
                break;
            } catch (Exception e) {
                log.error("处理统计任务时发生异常", e);
            }
        }
    }

    /**
     * 执行统计任务
     * @param userId 用户ID
     */
    private void executeCalculation(Long userId) {
        log.info("开始统计用户ID {} 的分数", userId);
        try {
            if (userScoreRecordApplicationService != null) {
                userScoreRecordApplicationService.calculateUserScore(userId);
            } else {
                log.warn("UserScoreRecordApplicationService未注入，无法执行统计任务");
            }
            log.info("用户ID {} 的分数统计完成", userId);
        } catch (Exception e) {
            log.error("统计用户ID {} 的分数时发生异常", userId, e);
        }
    }
}

